各位好,連假結束了不知道各位禮拜一的心情如何呢?
那麼今天的主題是 Modules 應該也是還蠻輕鬆的,下面是這個說明&補充系列的進度條,希望趕快結束他,感覺 30 天不太夠用啊(遠目
以下正文開始
Modules 讓我們可以組織 crate 讓程式更簡潔易懂,並且可以控制物件屬性屬於 private 的或是 public 的。
這邊我們就直接拿官網的例子來帶各位實作一下,以下節錄官網的說明,
In the restaurant industry, some parts of a restaurant are referred to as front of house and others as back of house. Front of house is where customers are; this is where hosts seat customers, servers take orders and payment, and bartenders make drinks. Back of house is where the chefs and cooks work in the kitchen, dishwashers clean up, and managers do administrative work.
因此我們會做一個餐廳的簡單模型,裡面沒有任何功能純粹架構而已。
首先我們開一個新專案,執行
$ cargo new --lib restaurant
然後調整內容如下,
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
各位可以看到 front_of_house 這個 mod 裡面還有其他的 mod,藉著 module 我們可以把同類型的功能再把他 group 再一起做更多層的分類。
上一篇有提到 src/main.rs 跟 src/lib.rs 是 crate root,這是因為他們會在 module tree 的最頂端。
crate
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment
想必我也不用多做介紹因為 module tree 的概念就跟我們在 OS 上的檔案夾是相似的,層層劃分不同的功能並且歸檔就是 module 的概念。
那麼基本概念就完成了接下來要介紹要怎麼取得 module tree 裡面的程式。
在 Rust 我們使用 path 來取得我們需要的程式就像是一般 OS 的檔案路徑那樣,而 Path 有分成兩種,
crate
字符這兩種方式都是使用雙引號(::
)來分割目前的路徑。
接著讓我們回到剛剛的例子我們要怎麼使用 add_to_waitlist
這支程式呢?我們提供兩種方式來調用他,現在讓我們多增加一個 public 的函式 eat_at_restaurant
,
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
在 eat_at_restaurant
裡面我們用了絕對路徑和相對路經的方式來呼叫 add_to_waitlist
這支程式,各位可以同樣用檔案系統來想像,絕對路徑類似這樣 /front_of_house/hosting/add_to_waitlist
,可以把 crate
當成根目錄的 /
,反之相對路徑亦然。
要使用絕對路徑或相對路徑就取決於你要如何架構你的程式碼,例如使用相對路徑比較可以防止在調整檔案結構時所發生的錯誤,例如官網舉得例子,
For example, if we move the front_of_house module and the eat_at_restaurant function into a module named customer_experience, we’d need to update the absolute path to add_to_waitlist, but the relative path would still be valid
那麼就讓我們來 build 看看這支程式,
$ cargo build
$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0603]: module `hosting` is private
--> src/lib.rs:9:28
|
9 | crate::front_of_house::hosting::add_to_waitlist();
| ^^^^^^^
error[E0603]: module `hosting` is private
--> src/lib.rs:12:21
|
12 | front_of_house::hosting::add_to_waitlist();
| ^^^^^^^
錯誤訊息說 module hosting 是 private 的所以我們無法存取他。
Module 不只讓我們可以架構程式也讓我們擁有 privacy boundary
,而這跟 JS 差異就蠻大的 JS 基本上沒有這樣的設計只能透過命名區分差異。
而在 Rust 裡面所有的物件 (functions, methods, structs, enums, modules, and constants) 預設都是 private 的,父 module 不能使用子 module 但是子 module 的可以使用父 module 的物件,原因是子 module 包裝並隱藏了實作細節但是可以看到實作的 context (上下文)。
從上面餐廳的例子可以想像成顧客不會知道廚房在做什麼但是餐廳經理可以掌控裡面的一切。
總之 Rust 的設計是物件預設都是 private 的只有當你使用 pub
這個語法才可以讓物件變成是 public。
今天介紹了 modules 還有怎麼透過 path 的方式來使用它並且瞭解了 Rust 物件預設是 private 的設計,明天會繼續把這個章節完成。
那麼我們明天見!
ch07-02-defining-modules-to-control-scope-and-privacy
ch07-03-paths-for-referring-to-an-item-in-the-module-tree